#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "util/config.h"
#include "util/inotify.h"
#include "util/sync.h"
#include "util/file.h"
#include "util/strings.h"

#include "util/db_impl.h"
#include "util/log.h"
#include "util/app.h"

#include <string>
#include <stdint.h>

#include "util/threadpool.h"

using namespace std;

#define APP_NAME "sync-server"
#define APP_VERSION "1.0"

class MyApplication : public Application
{
    public :
    virtual void usage(int argc, char **argv);
    virtual void welcome();
    virtual void run();};

void MyApplication::welcome() {
    fprintf(stderr, "%s %s\n", APP_NAME, APP_VERSION);
    fprintf(stderr, "\n");
}

void MyApplication::usage(int argc, char **argv) {
    printf("Usage:\n");
    printf("    %s [-d] /path/to/sync.conf [-s start|stop|restart]\n", argv[0]);
    printf("Options:\n");
    printf("    -d    run as daemon\n");
    printf("    -s    option to start|stop|restart the server\n");
    printf("    -h    show this message\n");
}

void MyApplication::run() {
    std::string sync_path = conf->get_str("sync.path");
    std::string data_db_dir = conf->get_str("db_path");

    log_info("sync-server %s", APP_VERSION);
    log_info("conf_file        : %s", app_args.conf_file.c_str());
    log_info("log_level        : %s", Logger::shared()->level_name().c_str());
    log_info("log_output       : %s", Logger::shared()->output_name().c_str());
    log_info("log_rotate_size  : %" PRId64, Logger::shared()->rotate_size());

    log_info("main_db          : %s", data_db_dir.c_str());
    log_info("pidfile: %s, pid: %d", app_args.pidfile.c_str(), (int) getpid());
    log_info("sync server started.");

    //DBImpl *db = new DBImpl(data_db_dir);

    int ev_pipefd[2], sig_pipefd[2], ret;
    ret = socketpair(PF_UNIX, SOCK_STREAM, 0, ev_pipefd);
    if (ret < 0) {
        log_info("create event pipe error.   pipefd[0]:%d pipefd[1]:%d\n", ev_pipefd[0], ev_pipefd[1]);
    }
    ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sig_pipefd);
    if (ret < 0) {
        log_info("create sig pipe error.   pipefd[0]:%d pipefd[1]:%d\n", ev_pipefd[0], ev_pipefd[1]);
    }

    Inotify *inot = new Inotify(conf, ev_pipefd[0]);
    inot->set_mask(IN_CREATE | IN_MODIFY | IN_DELETE | IN_MOVED_TO | IN_ATTRIB); //IN_ALL_EVENTS 

    threadpool< std::string >* pool = NULL;
    pool = new threadpool< std::string >(8, 1000000, inot);

    watch_dir_thread(pool, inot, sync_path);

    //inot->recur_watch_dir(inot->inotify_fd, sync_path.c_str(), inot->mask);

    Sync *sync = new Sync(conf, ev_pipefd[1]);

    pid_t pid = fork();
    assert(pid >= 0);
    if (pid > 0) {
        close(ev_pipefd[1]); /* 父进程中关闭读通道 */
        log_info("monitor process is running.");
        inot->process_inotify_events(inot->q, inot->inotify_fd);
    } else {
        close(ev_pipefd[0]); /* 子进程中关闭写通道 */
        log_info("sync process is running.");
        sync->run();
    }
    delete pool;
    delete sync;
    //delete conf; 谁创建谁释放 app::main 创建 app::man 释放
    delete inot;

    log_info("%s exit.", APP_NAME);
}

int main(int argc, char** argv) {
    MyApplication app;
    return app.main(argc, argv);
    return 1;
}
